package com.bfsuolframework.core.dao.support;

import java.util.LinkedList;
import java.util.List;

/**
 * 例子：hql语句 select * from User u left join u.groups g left join g.roles r where r.id=5 and g.id=5
 * a = new HqlHelper('User', 'u')
 * if(gId !=null){
 * 	a.addLeftJoin('u.groups', 'g').addWhere('g.id=:gId');
 * }
 * if(rId !=null){
 * 	a.addLeftJoin('u.groups', 'g').addLeftJoin('g.roles', 'r').addWhere('r.id=:rId');
 * }
 * String hql = a.getSelectHql("select distinct u");
 * String hql = a.getCountHql("select count(distinct u.id)");
 * @author silane
 *
 */
public class HqlHelper {
	
	private List<JoinSegment> joinList = new LinkedList<JoinSegment>(); 
	
	private List<String> whereList = new LinkedList<String>(); 
	private List<String> havingList = new LinkedList<String>(); 
	private List<String> orderList = new LinkedList<String>(); 
	
	private String className;
	private String aliasName;
	private String groupBy;
	
	public static enum JOIN_TYPE  {INNER,LEFT,RIGHT};
	
	public HqlHelper(String className,String aliasName){
		this.className = className;
		this.aliasName = aliasName;
	}
	/**
	 * 添加一个新的Hql语句
	 * @param className 类名
	 * @param aliasName 类别名
	 * @return
	 */
	public com.bfsuolframework.core.dao.support.HqlHelper newHQL(String className, String aliasName){
		return new com.bfsuolframework.core.dao.support.HqlHelper(className, aliasName);
	}
	/**
	 * 添加一个内连接
	 * @param property 连接名
	 * @param aliasName 连接别名
	 * @return
	 */
	public com.bfsuolframework.core.dao.support.HqlHelper addInnerJoin(String property, String aliasName){
		addJoin(property, aliasName, JOIN_TYPE.INNER);
		return this;
	}
	/**
	 * 添加一个左连接
	 * @param property 连接名
	 * @param aliasName 连接别名
	 * @return
	 */
	public com.bfsuolframework.core.dao.support.HqlHelper addLeftJoin(String property, String aliasName){
		addJoin(property, aliasName, JOIN_TYPE.LEFT);
		return this;
	}
	/**
	 * 添加一个右连接
	 * @param property 连接名
	 * @param aliasName 连接别名
	 * @return
	 */
	public com.bfsuolframework.core.dao.support.HqlHelper addRightJoin(String property, String aliasName){
		addJoin(property, aliasName, JOIN_TYPE.RIGHT);
		return this;
	}
	/**
	 * 添加一个表间关联
	 * @param property 连接名
	 * @param aliasName 连接别名
	 * @param joinType 连接类型：内，左，右
	 */
	
	private void addJoin(String property, String aliasName, JOIN_TYPE joinType){
		JoinSegment join = new JoinSegment(property,aliasName,joinType);
		if(!joinList.contains(join)){
			joinList.add(join);
		}
	}
	/**
	 * 添加一个查询条件，全部使用and连接，如果有需要or连接的，需要实现拼接成hql对应的字符串
	 * @param where 条件
	 * @return
	 */
	public com.bfsuolframework.core.dao.support.HqlHelper addQuery(String where){
		whereList.add(where);
		return this;
	}
	/**
	 * 添加一个Having条件，全部使用and连接，如果有需要or连接的，需要实现拼接成hql对应的字符串
	 * @param having 条件
	 * @return
	 */
	public com.bfsuolframework.core.dao.support.HqlHelper addHaving(String having){
		havingList.add(having);
		return this;
	}
	/**
	 * 添加一个Group By分组
	 * @param groupBy 分组
	 * @return
	 */
	public com.bfsuolframework.core.dao.support.HqlHelper addGroupBy(String groupBy){
		this.groupBy = groupBy;
		return this;
	}
	/**
	 * 添加一个排序，方向需要写在参数中
	 * @param order 排序
	 * @return
	 */
	public com.bfsuolframework.core.dao.support.HqlHelper addOrder(String order){
		orderList.add(order);
		return this;
	}
	/**
	 * 返回列表对应的hql语句
	 * @return
	 */
	public String getSelectHQL(){
		return getSelectHQL(null);
	}
	/**
	 * 返回列表对应的hql语句
	 * @param select 返回查询对应的语句
	 * @return
	 */
	public String getSelectHQL(String select){
		StringBuffer sb = new StringBuffer();
		if(select != null && !select.trim().equals("")){
			if(!select.trim().toLowerCase().startsWith("select")){
				sb.append("SELECT ");
			}
			sb.append(select).append(" ");
		}
		sb = genWhere(sb);
		sb = genOrder(sb);
		
		return sb.toString();
	}
	/**
	 * 返回数量对应的hql语句
	 * @return
	 */
	public String getCountHQL(){
		return getCountHQL(null);
	}
	/**
	 * 返回数量对应的hql语句
	 * @param count 计算数量的语句，默认用count(*)
	 * @return
	 */
	public String getCountHQL(String count){
		StringBuffer sb = new StringBuffer();
		if(count != null && !count.trim().equals("")){
			if(!count.trim().toLowerCase().startsWith("select")){
				sb.append("SELECT ");
			}
			sb.append(count).append(" ");
		}else{
			sb.append("SELECT COUNT(*) ");
		}
		sb = genWhere(sb);
		
		return sb.toString();
	}
	/**
	 * 生成hql中的条件和表关联
	 * @param sb
	 * @return
	 */
	private StringBuffer genWhere(StringBuffer sb){
		sb.append("FROM ").append(className).append(" ").append(aliasName);
		if(!joinList.isEmpty()){
			for(JoinSegment join : joinList){
				switch (join.joinType){
				case INNER:
					sb.append(" inner join ");
					break;
				case LEFT:
					sb.append(" left join ");
					break;
				case RIGHT:
					sb.append(" right join ");
				}
				sb.append(join.property).append(" ").append(join.aliasName);
			}
		}
		if(!whereList.isEmpty()){
			sb.append(" WHERE ");
			boolean first = true;
			for(String where : whereList){
				if(first){
					sb.append(where);
					first = false;
				}else{
					sb.append(" AND ").append(where);
				}
			}
		}
		if(groupBy != null && !groupBy.equals("")){
			sb.append(" GROUP BY ").append(groupBy);
			
			if(!havingList.isEmpty()){
				sb.append(" HAVING ");
				boolean first = true;
				for(String having : havingList){
					if(first){
						sb.append(having);
						first = false;
					}else{
						sb.append(" AND ").append(having);
					}
				}
			}
		}
		return sb;
	}
	/**
	 * 生成hql中的排序字段
	 * @param sb
	 * @return
	 */
	private StringBuffer genOrder(StringBuffer sb){
		if(!orderList.isEmpty()){
			sb.append(" ORDER BY ");
			boolean first = true;
			for(String order : orderList){
				if(first){
					sb.append(order);
					first = false;
				}else{
					sb.append(" , ").append(order);
				}
			}
		}
		return sb;
	}
	/**
	 * 内部类，保存关联表的信息
	 * @author silane
	 *
	 */
	private class JoinSegment{
		private String property;//属性
		private String aliasName;//别名
		private JOIN_TYPE joinType;//类型
		
		/**
		 * @param property
		 * @param aliasName
		 * @param joinType
		 */
		public JoinSegment(String property, String aliasName, JOIN_TYPE joinType) {
			this.property = property;
			this.aliasName = aliasName;
			this.joinType = joinType;
		}
		/**
		 * @return the property
		 */
		public String getProperty() {
			return property;
		}
		/**
		 * @param property the property to set
		 */
		@SuppressWarnings("unused")
		public void setProperty(String property) {
			this.property = property;
		}
		/**
		 * @return the aliasName
		 */
		@SuppressWarnings("unused")
		public String getAliasName() {
			return aliasName;
		}
		/**
		 * @param aliasName the aliasName to set
		 */
		@SuppressWarnings("unused")
		public void setAliasName(String aliasName) {
			this.aliasName = aliasName;
		}
		/**
		 * @return the joinType
		 */
		@SuppressWarnings("unused")
		public JOIN_TYPE getJoinType() {
			return joinType;
		}
		/**
		 * @param joinType the joinType to set
		 */
		@SuppressWarnings("unused")
		public void setJoinType(JOIN_TYPE joinType) {
			this.joinType = joinType;
		}
		
		@Override
		public boolean equals(Object obj) {
			if(obj == null){
				return false;
			}
			if (this == obj){
				return true;
			}
			if (!getClass().equals(obj.getClass())){
				return false;
			}
			
			JoinSegment that = (JoinSegment)obj;
			if(!getProperty().equals(that.getProperty())){
				return false;
			}
			
			return true;
		}

		/**
		 * 返回该对象的哈希码值
		 */
		@Override
		public int hashCode() {
			
			int result = 17;
			
			result = result * 31 + (getClass().getName().hashCode());
			result = result * 31 + (getProperty()==null?0:getProperty().hashCode());
			
			return result;
		}

	}
}
